package com.eec.AOP;

import com.eec.AOP.annotation.*;
import com.eec.AOP.responsibility.Responsibility;
import com.eec.AOP.responsibility.ResponsibilityAfter;
import com.eec.AOP.responsibility.ResponsibilityAround;
import com.eec.AOP.responsibility.ResponsibilityBefore;
import com.eec.spring.ApplicationContent;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author LeeC
 * @description
 * @date 2025/8/16
 * @PACKAGE_NAME com.eec.AOP.Aspect
 */
public class Chain {
    public int chainIndex ;
    public static List<Responsibility> responsibilityChain = new ArrayList<>();
    private final Method method;
    private final Object[] args;
    private final Object target;
    public ConcurrentHashMap<Class<?>, Integer> methodMap = null;
    public Chain(Method method, Object[] args, Object target){
        this.method = method;
        this.args = args;
        this.target = target;
        if(responsibilityChain.isEmpty()){
            responsibilityChain = Chain.getResponsibilityChain();
        }
        chainIndex = 0;
    }
    /**
     * 这里要根据具体的类来对修改责任链进行判断
     */
    public Object proceed(){
        if(chainIndex >= responsibilityChain.size()){
            return ExecuteMethod();
        }
        // 对应的责任
        Responsibility responsibility = responsibilityChain.get(chainIndex++);
        // 构建对应方法的 注解缓存
        if(methodMap == null){
            initMethodMap();
        }
        // 存在则需要加到执行链
        // 方法上 存在此责任链的注解
        if(methodMap.containsKey(responsibility.getAnnotationClass())){
            return responsibility.invoke(this);
        }
        // 不存在对应的注解则切换到下一个 责任链
        else {
            return proceed();
        }
    }

    public Object ExecuteMethod(){
        try {
            return method.invoke(target,args);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 构建 方法对应的注解缓存
     */
    public void initMethodMap(){
        methodMap = new ConcurrentHashMap<>();
        Annotation[] annotations = method.getAnnotations();
        for (Annotation annotation : annotations){
            if(!methodMap.containsKey(annotation.annotationType())){
                Class<? extends Annotation> aClass = annotation.annotationType();
                methodMap.put(aClass,1);
            }
        }
    }


    public static List<Responsibility> getResponsibilityChain() {
        String packageName = ApplicationContent.basePackage;
        List<File> javaFiles = new ArrayList<>();
        List<Responsibility> chain = new ArrayList<>();

        try {
            traverseJavaFiles(packageName,javaFiles);

            if(javaFiles.isEmpty()){
                return chain;
            }

            // 3. 遍历Java文件并加载类
            for (File file : javaFiles) {
                // 3.1 计算文件绝对路径，并统一替换为 '/' 分隔符（跨平台兼容）
                String filePath = file.getAbsolutePath().replace(File.separator, "/");

                // 3.2 处理包名：将包名（如 com.eec.AOP）转换为路径格式（com/eec/AOP）
                String packagePath = packageName.replace(".", "/");

                // 3.3 找到包路径在文件路径中的起始位置，截取相对路径
                int packageStartIndex = filePath.indexOf(packagePath);
                if (packageStartIndex == -1) {
                    // 文件不在在目标包下，跳过处理
                    continue;
                }

                // 截取包路径之后的部分（包含包目录开始的相对路径）
                // 例如：filePath = "/project/com/eec/AOP/MyAspect.java"
                // packagePath = "com/eec/AOP" → 截取后为 "MyAspect.java"
                String relativePath = filePath.substring(packageStartIndex + packagePath.length() + 1);

                // 3.4 转换为全类名：去掉 .java 后缀，将 '/' 替换为 '.'，再拼接包名
                String className = packageName + "." + relativePath.replace(".class", "").replace("/", ".");
                // 最终结果示例：com.eec.AOP.MyAspect

                // 3.3 加载类并处理（例如判断是否有@Aspect注解）
                Class<?> aClass = Class.forName(className);
                if (aClass.isAnnotationPresent(Aspect.class)) {
                    // 创建Responsibility实例并添加到链中

                    // 获取pointCut 对应的注解类
                    Class<?> pointCut = null;
                    Method[] methods = aClass.getMethods();
                    for (Method method : methods){
                        if (method.isAnnotationPresent(Pointcut.class)){
                            String value = method.getAnnotation(Pointcut.class).value();
                            // 获取className
                            pointCut = Class.forName(value);
                            break;
                        }
                    }
                    if(pointCut == null){
                        throw new RuntimeException("没有找到切点");
                    }
                    for (Method method : methods){
                        // Before 责任执行 判定自己是否被此注解标记
                        if (method.isAnnotationPresent(Before.class)) {
                            chain.add(new ResponsibilityBefore(pointCut,method,aClass));
                        } else if (method.isAnnotationPresent(After.class)) {
                            chain.add(new ResponsibilityAfter(pointCut,method,aClass));
                        } else if (method.isAnnotationPresent(Around.class)) {
                            chain.add(new ResponsibilityAround(pointCut,method,aClass));
                        }
                    }
                }
            }
        } catch (URISyntaxException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        // 对 chain 链进行排序
        chain.sort(new Comparator<Responsibility>(){
            @Override
            public int compare(Responsibility o1, Responsibility o2) {
                // Around 通知应该最先执行，因为它需要控制整个执行流程
                if (o1 instanceof ResponsibilityAround)
                    return -1;
                if (o2 instanceof ResponsibilityAround)
                    return 1;

                int o1Order = 0 , o2Order = 0;
                if(o1 instanceof ResponsibilityBefore )
                    o1Order = 1;
                if(o1 instanceof ResponsibilityAfter )
                    o1Order = 3;
                if(o2 instanceof ResponsibilityBefore )
                    o2Order = 1;
                if(o2 instanceof ResponsibilityAfter )
                    o2Order = 3;
                return o1Order - o2Order;
            }
        });
        return chain;
    }
    /**
     * 遍历指定包路径下的所有Java文件
     *
     * @param packageName 包名（如：com.eec.AOP）
     */
    private static void traverseJavaFiles(String packageName, List<File> javaFiles)
            throws URISyntaxException {
        packageName = packageName.replace(".", "/");
        // 扫描ScanPath包下的所有类
        URL resource = ApplicationContent.class.getClassLoader().getResource(packageName);
        // 获取到文件夹

        File file = new File(resource.getFile());
        getFiles(file.listFiles(), javaFiles);
    }

    private static void getFiles(File[] directory, List<File> javaFiles) throws URISyntaxException {
        if (directory == null) {
            return;
        }
        for (File file : directory) {
            if (file.isDirectory()) {
                getFiles(file.listFiles(), javaFiles);
            } else if (file.getName().endsWith(".class")) {
                javaFiles.add(file);
            }
        }
    }

}
